package org.pp.openapi.service.impl;

import com.github.pagehelper.PageInfo;
import org.pp.openapi.common.ApiException;
import org.pp.openapi.common.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.pp.openapi.consts.SqlType;
import org.pp.openapi.domain.ApiSql;
import org.pp.openapi.parser.DataParser;
import org.pp.openapi.parser.QueryParser;
import org.pp.openapi.service.*;
import org.pp.openapi.vo.*;
import org.pp.openapi.utils.JsUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
@Slf4j
public class OpenDataServiceImpl implements IOpenDataService {
    @Autowired
    private IApiLoaderService apiLoaderService;
    @Autowired
    private IDbService dbService;

    @Override
    public ApiResult run(HttpServletRequest request, String body) {
        String method = request.getMethod().toUpperCase();
        ApiResult ret = null;
        switch (method){
            case "GET":
                ret =  ApiResult.success(doGet(request.getQueryString()));
                break;
            case "DELETE":
                ret = ApiResult.success(doDelete(request.getQueryString()));
                break;
            case "POST":
                ret = ApiResult.success(doPost(body));
                break;
            case "PUT":
                ret = ApiResult.success(doPut(body));
                break;
            case "PATCH":
                ret = ApiResult.success(doPatch(body));
                break;
            default:
                ret = ApiResult.error("不支持方法:" + method);
                break;
        }
        return ret;
    }

    /**
     * 查询
     * @param paramsStr
     * @return
     */
    @Override
    public Map doGet(String paramsStr){
        TableQuery query = QueryParser.parse(paramsStr);
        Map retData = new HashMap();
        //多表非联表查询
        if(query instanceof RelQuery &&!((RelQuery)query).getSubs().isEmpty()){
            //先查主表数据
            RelQuery rel = (RelQuery)query;
            TableQuery table = rel.getMainTable();
            retData.put(table.getTable(), dbService.find(table));
            //再查子表数据
            Iterator<String> it = rel.getSubs().keySet().iterator();
            while(it.hasNext()){
                table = rel.getSubs().get(it.next());
                for(String p:table.getData().keySet()){
                    //自动填充参数
                    String v = table.getData().get(p).toString();
                    if(v.startsWith("@")){
                        String[] ps = v.split("\\.");
                        String pname = ps[0].substring(1);
                        if(!retData.containsKey(pname)){
                            throw new ApiException("查询数据的业务逻辑异常");
                        }
                        table.getData().put(p, ((Map)retData.get(pname)).get(ps[1]));
                    }
                }
                if(table.getPager() != null){
                    retData.put(table.getTable(), dbService.query(table));
                }else {
                    retData.put(table.getTable(), dbService.find(table));
                }
            }
        }else{
            //单表查询
            if(query.getPager() == null){
                retData = dbService.find(query);
            }else{
                SqlPager pager = query.getPager();
                List<Map> list = dbService.query(query);
                retData.put("rows", list);
                retData.put("page", pager.getPage());
                retData.put("limit", pager.getLimit());
                retData.put("total", new PageInfo(list).getTotal());
            }
        }
        return retData;
    }


    /**
     * 删除
     * @param paramsStr
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int doDelete(String paramsStr){
        int rows = 0;
        List<TableQuery> list = DataParser.parseDelete(paramsStr);
        SqlPager pager = new SqlPager(10000, 1);
        for(TableQuery table:list){
            table.setPager(pager);
            rows += dbService.deleteData(table);
        }
        return rows;
    }

    /**
     * 新增数据，如果模型配置了唯一字段，就会唯一字段做查询判断是否有旧数据，如果有旧数据，就认为是重复，报错
     * @param paramsStr
     * @return
     */
    @Override
    @Transactional
    public Map doPost(String paramsStr){
        RelData data = DataParser.parseData(paramsStr);
        Map<String, Map> retMap = new HashMap<>();
        for(TableData table: data.getTables()){
            table.setIgnore(data.getIgnore());
            Map<String, Object> dataMap = table.getData();
            dbService.fillData(retMap, dataMap);
            dbService.insertData(table, false);
            retMap.put(table.getTable(), dataMap);
        }
        return retMap;
    }

    /**
     * 更新数据，需要有主键数据，没有就报错
     * @param paramsStr
     * @return
     */
    @Override
    public int doPut(String paramsStr){
        int rows = 0;
        RelData data = DataParser.parseData(paramsStr);
        Map<String, Map> retMap = new HashMap<>();
        for(TableData table: data.getTables()){
            table.setIgnore(data.getIgnore());
            Map<String, Object> dataMap = table.getData();
            dbService.fillData(retMap, dataMap);
            rows += dbService.updateData(table);
            retMap.put(table.getTable(), dataMap);
        }
        return rows;
    }

    /**
     * 更新或新增
     * 如果带有主键数据，会查询是否有旧数据：如果有旧数据会自动更新，没有旧数据会新增
     * 如果没有主键数据，但是模型配置了唯一字段，会按唯一字段做查询判断是否有旧数据：有旧数据就更新，没有旧数据就新增
     * @param paramsStr
     * @return
     */
    @Override
    public int doPatch(String paramsStr){
        int rows = 0;
        RelData data = DataParser.parseData(paramsStr);
        Map<String, Map> retMap = new HashMap<>();
        for(TableData table: data.getTables()){
            table.setIgnore(data.getIgnore());
            Map<String, Object> dataMap = table.getData();
            dbService.fillData(retMap, dataMap);
            rows += dbService.insertData(table, true);
            retMap.put(table.getTable(), dataMap);
        }
        return rows;
    }

    /**
     * 查询数据源，支持类型是统计报表，列表查询和计算，不支持子查询和批处理
     * @param dsCode
     * @param params
     * @return
     */
    @Override
    public Object doDs(String dsCode, Map params){
        ApiSql apiSql = apiLoaderService.getSql(dsCode);
        if(apiSql == null){
            throw new ApiException("数据源不存在");
        }
        //批量操作和子查询不支持直接调用
        if(apiSql.getType().equalsIgnoreCase(SqlType.BATCH.getCode()) || apiSql.getType().equalsIgnoreCase(SqlType.INNER.getCode())){
            throw new ApiException("不支持的操作");
        }
        //生成SQL
        String sql = apiSql.isFun() ? JsUtil.exec(apiSql.getContent(), params) : apiSql.getContent();
        List<Map> list = dbService.query(sql);
        if(list == null || list.isEmpty()){
            return null;
        }
        //计算结果只返回一个值
        if(apiSql.getType().equalsIgnoreCase(SqlType.COUNT.getCode())){
            return list.get(0).values().iterator().next();
        }else{
            //统计报表和列表查询返回全部
            return list;
        }
    }
}
